﻿// -------------------------------------------------------------------------
//    @FileName         :    NFCacheDataLoadTransTemplate.h
//    @Author           :    Gao.Yi
//    @Date             :    2025-08-11
//    @Email			:    445267987@qq.com
//    @Module           :    NFCacheDataLoadTransTemplate
//    @Desc             :    缓存数据加载事务模板类
//                           基于模板模式封装缓存数据查询流程，支持不同Protobuf类型的复用
//                           提供批量/单条查询的完整事务处理
//
// -------------------------------------------------------------------------

/**
 * @file NFCacheDataTransTemplate.h
 * @brief 缓存数据获取事务模板
 *
 * 基于事务框架封装的缓存数据选择（批量/单条）流程模板：
 * - 封装了DB选择请求发送
 * - 处理选择结果并回调上层批量事务
 * - 通过模板参数复用不同PB类型
 */
#pragma once

#include "NFCacheDataGetTrans.h"
#include "NFCacheDataLoadTrans.h"
#include "NFIServerMessageModule.h"
#include "ServerCommon.nanopb.h"
#include "NFComm/NFObjCommon/NFObject.h"
#include "NFComm/NFObjCommon/NFTransBase.h"

/**
 * @tparam className 具体事务类名（CRTP模式）
 * @tparam pbClass   缓存数据对应的Protobuf类型
 * @tparam classType 共享内存对象类型枚举
 * 
 * @brief 缓存数据加载事务模板类
 * 
 * 基于模板模式封装缓存数据查询的完整流程：
 * 1. 批量查询：支持多条记录的并发查询
 * 2. 单条查询：支持单条记录的精确查询
 * 3. 结果处理：自动解析Protobuf数据并添加到缓存
 * 4. 事务回调：完成后回调上层批量事务
 * 
 * 使用方式：
 * - 继承此类并实现 AddCacheData() 方法
 * - 通过模板参数指定具体的Protobuf类型
 * - 支持批量/单条查询的完整事务流程
 * 
 * 设计特点：
 * - 使用CRTP模式实现编译时多态
 * - 通过模板参数支持不同Protobuf类型的复用
 * - 提供完整的错误处理和事务管理
 * - 支持批量查询的分批处理机制
 */
template <typename className, typename pbClass, int classType>
class NFCacheDataLoadTransTemplate : public NF_OBJECT_TEMPLATE_MACRO(className, classType, NFCacheDataLoadTrans)
public:
    /**
     * @brief 构造函数，根据共享内存模式进行初始化
     * 
     * 根据共享内存管理器的创建模式选择初始化方式：
     * - EN_OBJ_MODE_INIT：冷启动模式，调用 CreateInit() 进行完整初始化
     * - 其他模式：热启动模式，调用 ResumeInit() 进行恢复初始化
     */
    NFCacheDataLoadTransTemplate()
    {
        if (EN_OBJ_MODE_INIT == NFShmMgr::Instance()->GetCreateMode())
        {
            CreateInit();
        }
        else
        {
            ResumeInit();
        }
    }

    /**
     * @brief 析构函数
     * 
     * 清理资源，由于使用共享内存管理，通常无需特殊处理
     */
    ~NFCacheDataLoadTransTemplate() override
    {
    }

    /**
     * @brief 冷启动创建初始化
     * 
     * 在共享内存冷启动场景下，对新创建的事务对象进行初始化
     * 当前实现为空，如有需要可在此添加初始化逻辑
     * 
     * @return 0 表示成功
     */
    int CreateInit()
    {
        return 0;
    }

    /**
     * @brief 热启动恢复初始化
     * 
     * 在共享内存热启动场景下，从持久化数据恢复事务状态时调用
     * 当前实现为空，如有需要可在此添加恢复逻辑
     * 
     * @return 0 表示成功
     */
    int ResumeInit()
    {
        return 0;
    }

public:
    /**
     * @brief 批量查询请求
     * 
     * 向存储服务器发送批量查询请求：
     * 1. 保存查询原因
     * 2. 将ID列表转换为字符串格式的主键列表
     * 3. 发送批量查询请求
     * 4. 支持分批处理，避免单次查询数据量过大
     * 
     * @param vecId    包含查询目标ID的向量
     * @param enReason 查询原因/场景标识
     * @return 0 表示成功，其他值为错误码
     */
    int LoadCacheDataBatchReq(const std::vector<uint64_t>& vecId, int enReason) override
    {
        this->m_ullTargetId = 0;
        this->m_iReason = enReason;
        std::vector<std::string> vecPrivateKeys;
        for (size_t i = 0; i < vecId.size(); i++)
        {
            uint64_t ullId = vecId[i];
            if (ullId > 0)
            {
                vecPrivateKeys.push_back(NFCommon::tostr(ullId));
            }
        }

        int iRetCode = FindModule<NFIServerMessageModule>()->SendSelectTrans((NF_SERVER_TYPE)this->m_iServerType, 0, pbClass(), this->m_iTableId, this->GetGlobalId(), std::vector<std::string>(), vecPrivateKeys);
        CHECK_ERR(this->m_ullRoleId, iRetCode, "SendSelectTrans Failed, ullIds:{}", NFCommon::tostr(vecPrivateKeys));
        return 0;
    }

    /**
     * @brief 单条查询请求
     * 
     * 向存储服务器发送单条查询请求：
     * 1. 保存查询原因
     * 2. 构造Protobuf消息对象并设置主键
     * 3. 发送单条查询请求
     * 
     * @param ullId    查询目标ID
     * @param enReason 查询原因/场景标识
     * @return 0 表示成功，其他值为错误码
     */
    int LoadCacheDataSingleReq(uint64_t ullId, int enReason) override
    {
        pbClass pbCacheData;
        NFProtobufCommon::SetPrimarykeyFromMessage(&pbCacheData, NFCommon::tostr(ullId));
        return NFCacheDataLoadTrans::LoadCacheDataSingleReq(ullId, enReason, pbCacheData);
    }

    /**
     * @brief 批量查询返回处理（多条记录）
     * 
     * 处理存储服务器返回的批量查询结果：
     * 1. 验证返回结果和错误码
     * 2. 遍历所有记录，逐个解析Protobuf数据
     * 3. 调用 LoadCacheDataFromMessage() 将每条记录添加到缓存
     * 4. 检查是否为最后一批，如果是则完成事务
     * 
     * @param pRes     指向存储服务器返回的查询结果对象
     * @param errCode  错误码
     * @return 0 表示成功，其他值为错误码
     */
    int LoadCacheDataBatchRes(const NFrame::storesvr_sel_res* pRes, int32_t errCode) override
    {
        CHECK_NULL(0, pRes);
        if (this->m_iTransId <= 0)
        {
            return errCode;
        }

        NFCacheDataGetTrans* pTrans = NFCacheDataGetTrans::GetTrans(this->m_iTransId);
        CHECK_NULL_WF(this->m_ullRoleId, pTrans, "NFCacheDataGetTrans failed, transId:{}", this->m_iTransId);

        if (errCode != 0)
        {
            // 回调上层事务的结果处理方法
            int iRetCode = pTrans->GetCacheDataRes(this->m_ullTargetId, this->m_iTableId, this->m_iReason, errCode, nullptr);
            CHECK_ERR_AND_FIN_TRANS(iRetCode, pTrans, "{}::GetCacheDataRes Failed, m_ullRoleId:{}, m_ullTargetId:{} tableId:{}, reason:{}", pTrans->GetClassName(), this->m_ullRoleId, this->m_ullTargetId, this->m_iTableId, this->m_iReason);
        }
        else
        {
            // 处理所有查询记录
            if (pRes->record_size() > 0)
            {
                for (size_t i = 0; i < pRes->record_size(); i++)
                {
                    pbClass pbCacheData;
                    bool iRet = pbCacheData.ParseFromString(pRes->record(i));
                    CHECK_EXPR(iRet, -1, "ParseFromString Failed");

                    // 回调上层事务的结果处理方法
                    int iRetCode = pTrans->GetCacheDataRes(this->m_ullTargetId, this->m_iTableId, this->m_iReason, errCode, &pbCacheData);
                    CHECK_ERR_AND_FIN_TRANS(iRetCode, pTrans, "{}::GetCacheDataRes Failed, m_ullRoleId:{}, m_ullTargetId:{} tableId:{}, reason:{}", pTrans->GetClassName(), this->m_ullRoleId, this->m_ullTargetId, this->m_iTableId, this->m_iReason);
                }
            }
        }

        // 检查是否为最后一批，如果是则完成事务
        if (pRes->is_lastbatch())
        {
            this->SetFinished(0);
        }
        return 0;
    }

    /**
     * @brief 单条查询返回处理（单记录）
     * 
     * 处理存储服务器返回的单条查询结果：
     * 1. 验证返回结果和错误码
     * 2. 解析Protobuf消息数据
     * 3. 调用 LoadCacheDataFromMessage() 将数据添加到缓存
     * 4. 完成事务
     * 
     * @param pRes     指向存储服务器返回的查询结果对象
     * @param errCode  错误码
     * @return 0 表示成功，其他值为错误码
     */
    int LoadCacheDataSingleRes(const NFrame::storesvr_selobj_res* pRes, int32_t errCode) override
    {
        CHECK_NULL(this->m_ullRoleId, pRes);

        if (this->m_iTransId <= 0)
        {
            return errCode;
        }

        NFCacheDataGetTrans* pTrans = NFCacheDataGetTrans::GetTrans(this->m_iTransId);
        CHECK_NULL_WF(this->m_ullRoleId, pTrans, "NFCacheDataGetTrans failed, transId:{}", this->m_iTransId);

        if (errCode != 0)
        {
            // 回调上层事务的结果处理方法
            int iRetCode = pTrans->GetCacheDataRes(this->m_ullTargetId, this->m_iTableId, this->m_iReason, errCode, nullptr);
            CHECK_ERR_AND_FIN_TRANS(iRetCode, pTrans, "{}::GetCacheDataRes Failed, m_ullRoleId:{}, m_ullTargetId:{} tableId:{}, reason:{}", pTrans->GetClassName(), this->m_ullRoleId, this->m_ullTargetId, this->m_iTableId, this->m_iReason);
        }
        else
        {
            // 解析查询结果
            pbClass pbCacheData;
            bool bRet = pbCacheData.ParseFromString(pRes->record());
            if (!bRet)
            {
                CHECK_ERR(this->m_ullRoleId, -1, "{}::ParseFromString Failed", pbCacheData.GetTypeName());
            }

            // 回调上层事务的结果处理方法
            int iRetCode = pTrans->GetCacheDataRes(this->m_ullTargetId, this->m_iTableId, this->m_iReason, errCode, &pbCacheData);
            CHECK_ERR_AND_FIN_TRANS(iRetCode, pTrans, "{}::GetCacheDataRes Failed, m_ullRoleId:{}, m_ullTargetId:{} tableId:{}, reason:{}", pTrans->GetClassName(), this->m_ullRoleId, this->m_ullTargetId, this->m_iTableId, this->m_iReason);
        }


        this->SetFinished(0);
        return 0;
    }
};
